package main

import "fmt"

func main() {
   // chan 为派生类型 channel，后面可能会说吧
   var c1, c2, c3 chan int
   var i1, i2 int
   select {
	  // 这里猜测用 <-c1 表示将 c1 的值通信赋值给 i1，暂时不能完全理解，后面继续学习继续理解
      case i1 = <-c1:
         fmt.Printf("received ", i1, " from c1\n")
      case c2 <- i2:
		 fmt.Printf("sent ", i2, " to c2\n")
	  // 如果是两个变量来接收，那第二个变量指的是是否接收成功，如果第二个变量为 false，则说明该通信频道被关闭，暂时不能完全理解，后面继续学习继续理解
      case i3, ok := (<-c3):  // same as: i3, ok := <-c3
         if ok {
            fmt.Printf("received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed\n")
         }
      default:
         fmt.Printf("no communication\n")
   }    
}

/*
select 是 Go 中的一个控制结构，类似于用于通信的 switch 语句。每个 case 必须是一个通信操作，要么是发送要么是接收。

select 随机执行一个可运行的 case。如果没有 case 可运行，它将阻塞，直到有 case 可运行。一个默认的子句应该总是可运行的。

【语法】
Go 编程语言中 select 语句的语法如下：

select {
    case communication clause  :
       statement(s);      
    case communication clause  :
       statement(s); 
    // 你可以定义任意数量的 case
    default : // 可选
       statement(s);
}

以下描述了 select 语句的语法：

* 每个 case 都必须是一个通信
* 所有 channel 表达式都会被求值
* 所有被发送的表达式都会被求值
* 如果任意某个通信可以进行，它就执行，其他被忽略。
* 如果有多个 case 都可以运行，Select 会随机公平地选出一个执行。其他不会执行。 
  否则：
	1. 如果有 default 子句，则执行该语句。
	2. 如果没有 default 子句，select 将阻塞，直到某个通信可以运行；Go 不会重新对 channel 或值进行求值。
*/

// 这块的知识理解起来比较有难度，后续根据后续的教学内容再次进行理解。